#ifndef ZL_REGEX_EXPRESSION
#define ZL_REGEX_EXPRESSION

#include "RegexData.h"
#include "RegexAutomaton.h"
#include "../Basic/Pointer.h"
#include "../Basic/String.h"


namespace zl
{
	namespace regex_internal
	{
		using namespace zl::collections;
                class IRegexExpressionAlgorithm;

		class Expression:public Object,public NotCopyable
		{
		public:
			typedef Ptr<Expression>                             Ref;
			typedef Dictionary<std::wstring, Expression::Ref>         Map;
			virtual void           Apply(IRegexExpressionAlgorithm& algorithm)=0;
			bool                   HasNoExtension();
			bool                   CanTreatAsPure();
			bool                   IsEqual(Expression* expression);
			void                   NormalizeCharSet(CharRange::List &subset);
			void                   CollectCharSet(CharRange::List &subset);
			void                   ApplyCharSet(CharRange::List &subset);
			Automaton::Ref         GenerateEpsilonNfa();
		};

		class CharSetExpression:public Expression
		{
		public:
			CharRange::List        ranges;
			bool                   reverse;
			bool                   AddRangewithConflict(CharRange range);
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class LoopExpression:public Expression
		{
		public:
			int                    min;
			int                    max;
			bool                   preferlong;                
			Expression::Ref        expression;                
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class SequenceExpression:public Expression             
		{
		public:
			Expression::Ref        left;
			Expression::Ref        right;
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class AlternateExpression:public Expression             
		{
		public:
			Expression::Ref        left;
			Expression::Ref        right;
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class BeginExpression:public Expression
		{
		public:
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class EndExpression:public Expression
		{
		public:
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class CaptureExpression:public Expression
		{
		public:
			std::wstring           name;
			Expression::Ref        expression;        
			void                   Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class MatchExpression:public Expression
		{
		public:
			std::wstring            name;
			zint                    index;
			void                    Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class PositiveExpression:public Expression
		{
		public:
			Expression::Ref          expression; 
			void                     Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class NegativeExpression:public Expression
		{
		public:
			Expression::Ref           expression;
			void                      Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class UsingExpression:public Expression
		{
		public:
			std::wstring               name;
			void                       Apply(IRegexExpressionAlgorithm& algorithm);
		};

		class RegexExpression:public Object,public NotCopyable
		{
		public:
			typedef Ptr<RegexExpression>            Ref;
			Expression::Map            definitions; 
			Expression::Ref            expressions; 
			Expression::Ref            Merge();
		};



		
		class IRegexExpressionAlgorithm:public Interface
		{
		public:
			virtual void           Visit(CharSetExpression* expression)=0;
			virtual void           Visit(LoopExpression* expression)=0;
			virtual void           Visit(SequenceExpression* expression)=0;
			virtual void           Visit(AlternateExpression* expression)=0;
			virtual void           Visit(BeginExpression* expression)=0;
			virtual void           Visit(EndExpression* expression)=0;
			virtual void           Visit(CaptureExpression* expression)=0;
			virtual void           Visit(MatchExpression* expression)=0;
			virtual void           Visit(PositiveExpression* expression)=0;
			virtual void           Visit(UsingExpression* expression)=0;
			virtual void           Visit(NegativeExpression* expression)=0;
		};

		template<typename ReturnType,typename ParameterType=void*>
		class RegexExpressionAlgorithm:public Object,public IRegexExpressionAlgorithm
		{
		private:
			ReturnType              returnValue;
			ParameterType*          parameterValue;
		public:
			ReturnType              Invoke(Expression* expression,ParameterType parameter)
			{
				parameterValue=&parameter;
				expression->Apply(*this);
				return returnValue;
			}

			ReturnType              Invoke(Expression::Ref expression,ParameterType parameter)
			{
				parameterValue=&parameter;
				expression->Apply(*this);
				return returnValue;
			}

			virtual ReturnType       Apply(CharSetExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(LoopExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(SequenceExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(AlternateExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(BeginExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(EndExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(CaptureExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(MatchExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(PositiveExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(NegativeExpression* expression,ParameterType parameter)=0;
			virtual ReturnType       Apply(UsingExpression* expression,ParameterType parameterValue)=0;
		public:
			void                     Visit(CharSetExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(LoopExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(SequenceExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(AlternateExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(BeginExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(EndExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(CaptureExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(UsingExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(PositiveExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                     Visit(NegativeExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}

			void                      Visit(MatchExpression* expression)
			{
				returnValue=Apply(expression,*parameterValue);
			}
		};



		template<typename ParameterType>
		class RegexExpressionAlgorithm<void,ParameterType>:public Object,public IRegexExpressionAlgorithm
		{
		private:
			ParameterType*           parameterValue;
		public:
			public:
			void                     Invoke(Expression* expression,ParameterType parameter)
			{
				parameterValue=&parameter;
				expression->Apply(*this);
			}

			void                     Invoke(Expression::Ref expression,ParameterType parameter)
			{
				parameterValue=&parameter;
				expression->Apply(*this);
			}

			virtual void             Apply(CharSetExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(LoopExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(SequenceExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(AlternateExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(BeginExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(EndExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(CaptureExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(MatchExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(PositiveExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(NegativeExpression* expression,ParameterType parameter)=0;
			virtual void             Apply(UsingExpression* expression,ParameterType parameterValue)=0;
		public:
			void                     Visit(CharSetExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                     Visit(LoopExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                     Visit(SequenceExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                     Visit(AlternateExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(BeginExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(EndExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(UsingExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(MatchExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(CaptureExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(PositiveExpression* expression)
			{
				Apply(expression,*parameterValue);
			}

			void                      Visit(NegativeExpression* expression)
			{
				Apply(expression,*parameterValue);
			}
		};

		extern Ptr<LoopExpression>        ParseLoop(const wchar_t* &input);
		extern Ptr<Expression>            ParseUint(const wchar_t* &input);
		extern Ptr<Expression>            ParseCharset(const wchar_t* &input);
		extern Ptr<Expression>            ParseJoin(const wchar_t* &input);
		extern Ptr<Expression>            ParseAlt(const wchar_t* &input);
		extern Ptr<Expression>            ParseExpression(const wchar_t* &input);
		extern Ptr<Expression>            ParseFunction(const wchar_t* &input);
		extern RegexExpression::Ref       ParseRegexExpression(const std::wstring& code);

		extern std::wstring               EscapeTextForRegex(const std::wstring& literalString);
		extern std::wstring               UnescapeTextForRegex(const std::wstring& escapedText);
		extern std::wstring               NormalizeEscapedTextForRegex(const std::wstring& escapedText);
		extern bool                       IsRegexEscapedListeralString(const std::wstring& regex);
	};
};

#endif
